package com.smsc.headend.task.engine.handler.impl.deviceconfig;

import cn.hutool.core.convert.Convert;
import com.smsc.headend.common.enums.DeviceType;
import com.smsc.headend.common.enums.errorcode.TaskHandlerErrorCode;
import com.smsc.headend.common.utils.CosemUtils;
import com.smsc.headend.common.utils.CustomStringUtils;
import com.smsc.headend.module.asset.dmo.ComConfigDMO;
import com.smsc.headend.module.asset.entity.Meter;
import com.smsc.headend.module.common.AppName;
import com.smsc.headend.module.common.entity.DeviceOperation;
import com.smsc.headend.module.data.dto.DLMSSubDataItemDTO;
import com.smsc.headend.module.data.dto.DataItemDTO;
import com.smsc.headend.module.data.enums.DictionaryType;
import com.smsc.headend.module.data.enums.OperationGroup;
import com.smsc.headend.module.data.enums.OperationName;
import com.smsc.headend.module.protocol.DeviceData;
import com.smsc.headend.module.protocol.cosem.bo.CosemData;
import com.smsc.headend.module.task.dto.AtomicTask;
import com.smsc.headend.module.task.dto.Task;
import com.smsc.headend.task.engine.dao.TaskDAO;
import com.smsc.headend.task.engine.exception.UDISTaskHandlerException;
import com.smsc.headend.task.engine.facade.DataItemFacade;
import com.smsc.headend.task.engine.handler.TaskHandler;
import com.smsc.headend.task.engine.service.CosemXmlService;
import com.smsc.headend.task.engine.service.FeignAssetManagementService;
import com.smsc.headend.task.engine.service.asset.AssetService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.time.DateFormatUtils;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 71类 Limiter(读取loadLimit)
 * @author wxh
 * @date 2020/12/31 17:17
 */
@Slf4j
public class ReadLimiterHandler implements TaskHandler {
    public static final String SUB_TASK_COMPLETED = "subTaskCompleted";
    @Autowired
    CosemXmlService cosemXmlService;
    @Autowired
    FeignAssetManagementService assetManagementService;
    @Autowired
    TaskDAO taskDAO;
    @Autowired
    DataItemFacade dataItemFacade;
    @Autowired
    AssetService assetService;

    @Override
    public int handle(Task task, AtomicTask atomicTask, DeviceData deviceData, String actionResult) throws UDISTaskHandlerException {
        if (!(deviceData instanceof CosemData)) {
            throw new UDISTaskHandlerException(TaskHandlerErrorCode.DEVICE_DATA_TYPE_NOT_SUPPORT.toString());
        }
        CosemData cosemData = (CosemData) deviceData;
        OperationName operationName = OperationName.forId(atomicTask.getOperationId());
        Meter meter = assetManagementService.getMeterById(task.getMeterId());
        ComConfigDMO comConfigDMO = assetService.getComConfigById(task.getComId());
        DeviceOperation dictionary = assetService.getDictionary(atomicTask.getOperationId(), DictionaryType.Operation.getType());
        List<DataItemDTO> dataItemDTOList = dataItemFacade.getDataItemsByOperation(meter, null, dictionary, getParameterMap(task, atomicTask), comConfigDMO.getModelId());
        switch (operationName) {
            case GetMonitorValue:
                List<CosemData> monitorData = cosemData.getChild();
                if (monitorData.size() == 3) {
                    Integer classId = Convert.toInt(cosemXmlService.getData(monitorData.get(0).getType(), monitorData.get(0).getValue()));
                    String logicalName = (String)cosemXmlService.getData(monitorData.get(1).getType(), monitorData.get(1).getValue());
                    Integer attributeIndex = Convert.toInt(cosemXmlService.getData(monitorData.get(2).getType(), monitorData.get(2).getValue()));
                    DLMSSubDataItemDTO subDataItemDTO = new DLMSSubDataItemDTO();
                    subDataItemDTO.setAttributeId(attributeIndex);
                    subDataItemDTO.setClassId(classId);
                    subDataItemDTO.setObis(CustomStringUtils.parseHexObisCodeToInt(logicalName));
                    log.debug("Monitor DataItemDto", subDataItemDTO);
                    Long monitorDataItemId = assetManagementService.getSubDataItemIdByObisInfo(task.getMeterId(), CustomStringUtils.parseHexObisCodeToInt(logicalName), classId, attributeIndex, "ATTR", DeviceType.METER.getId());
                    //返回给web格式 subDataItemId;obis
                    String webValue = monitorDataItemId == null ? ""+ ";" + logicalName : Convert.toStr(monitorDataItemId) + ";" + logicalName;
                    taskDAO.addTaskData(task.getTaskNo(), atomicTask.getAtomicTaskNo(), operationName.getName(), webValue, 600L, true);
                }
                if (isSubTaskGroupLastAtomicTask(task, atomicTask)){
                    taskDAO.addTaskData(task.getTaskNo(), atomicTask.getAtomicTaskNo(), SUB_TASK_COMPLETED, true,600L, true);
                }
                break;
            case GetThresholdNormal:
                Object thresholdNormalData = cosemXmlService.getData(cosemData.getType(), cosemData.getValue());
                String normalValue =  Convert.toStr(assetManagementService.convertDataItemValWithUnit(meter.getModelId(), Convert.toLong(dataItemDTOList.get(0).getSubDataItemId()), Convert.toStr(thresholdNormalData), AppName.GUI.toString())[0]);
                taskDAO.addTaskData(task.getTaskNo(), atomicTask.getAtomicTaskNo(), operationName.getName(), normalValue, 600L, true);
                if (isSubTaskGroupLastAtomicTask(task, atomicTask)){
                    taskDAO.addTaskData(task.getTaskNo(), atomicTask.getAtomicTaskNo(), SUB_TASK_COMPLETED, true,600L, true);
                }
                break;
            case GetThresholdEmergency:
                Object thresholdEmergencyData = cosemXmlService.getData(cosemData.getType(), cosemData.getValue());
                String thresholdEValue = Convert.toStr(assetManagementService.convertDataItemValWithUnit(meter.getModelId(), Convert.toLong(dataItemDTOList.get(0).getSubDataItemId()), Convert.toStr(thresholdEmergencyData), AppName.GUI.toString())[0]);
                taskDAO.addTaskData(task.getTaskNo(), atomicTask.getAtomicTaskNo(), operationName.getName(), thresholdEValue, 600L, true);
                if (isSubTaskGroupLastAtomicTask(task, atomicTask)){
                    taskDAO.addTaskData(task.getTaskNo(), atomicTask.getAtomicTaskNo(), SUB_TASK_COMPLETED, true,600L, true);
                }
                break;
            case GetMinOverThresholdDuration:
                Object minOverThresholdDurationData = cosemXmlService.getData(cosemData.getType(), cosemData.getValue());
                taskDAO.addTaskData(task.getTaskNo(), atomicTask.getAtomicTaskNo(), operationName.getName(), minOverThresholdDurationData,  600L, true);
                if (isSubTaskGroupLastAtomicTask(task, atomicTask)){
                    taskDAO.addTaskData(task.getTaskNo(), atomicTask.getAtomicTaskNo(), SUB_TASK_COMPLETED, true,600L, true);
                }
                break;
            case GetMinUnderThresholdDuration:
                Object minUnderThresholdDurationData = cosemXmlService.getData(cosemData.getType(), cosemData.getValue());
                taskDAO.addTaskData(task.getTaskNo(), atomicTask.getAtomicTaskNo(), operationName.getName(), minUnderThresholdDurationData, 600L, true);
                if (isSubTaskGroupLastAtomicTask(task, atomicTask)){
                    taskDAO.addTaskData(task.getTaskNo(), atomicTask.getAtomicTaskNo(), SUB_TASK_COMPLETED, true,600L, true);
                }
                break;
            case GetEmergencyProfile:
                List<CosemData> emergencyProfileData = cosemData.getChild();
                if (emergencyProfileData.size() == 3) {
                    Convert.toInt(cosemXmlService.getData(emergencyProfileData.get(0).getType(), emergencyProfileData.get(0).getValue()));
                    String emergencyActivationTime = (String)cosemXmlService.getData(emergencyProfileData.get(1).getType(), emergencyProfileData.get(1).getValue());
                    Integer emergencyDuration= Convert.toInt(cosemXmlService.getData(emergencyProfileData.get(2).getType(), emergencyProfileData.get(2).getValue()));
                    if (CosemUtils.isDateTimeString(Convert.toStr(emergencyActivationTime))) {
                        emergencyActivationTime = DateFormatUtils.format(CosemUtils.parseOctStringDataTime(Convert.toStr(emergencyActivationTime)), "yyyy-MM-dd HH:mm:ss");
                    } else {
                        emergencyActivationTime = CosemUtils.parseOctStringDataTimeX(emergencyActivationTime);
                    }
                    Map<String, String> emergencyProfilemap = new HashMap<>();
                    emergencyProfilemap.put("emergencyActivationTime", emergencyActivationTime);
                    emergencyProfilemap.put("emergencyDuration", Convert.toStr(emergencyDuration));
                    taskDAO.addTaskData(task.getTaskNo(), atomicTask.getAtomicTaskNo(), operationName.getName(), emergencyProfilemap, 600L, true);
                }
                if (isSubTaskGroupLastAtomicTask(task, atomicTask)){
                    taskDAO.addTaskData(task.getTaskNo(), atomicTask.getAtomicTaskNo(), SUB_TASK_COMPLETED, true,600L, true);
                }
                break;
            case GetEmergencyProfileGroupIDList:
                List<CosemData> emergencyProfileGroupIdListData = cosemData.getChild();
                List<Integer> groupIds = new ArrayList<>();
                for (CosemData groupIdData: emergencyProfileGroupIdListData) {
                    Integer emergencyProfileGroupId = Convert.toInt(cosemXmlService.getData(groupIdData.getType(), groupIdData.getValue()));
                    groupIds.add(emergencyProfileGroupId);
                }
                taskDAO.addTaskData(task.getTaskNo(), atomicTask.getAtomicTaskNo(), operationName.getName(), groupIds, 600L, true);
                if (isSubTaskGroupLastAtomicTask(task, atomicTask)){
                    taskDAO.addTaskData(task.getTaskNo(), atomicTask.getAtomicTaskNo(), SUB_TASK_COMPLETED, true,600L, true);
                }
                break;
            case GetLoadLimitActions:
                List<CosemData> actionsDatas = cosemData.getChild();
                if (actionsDatas.size() == 2) {
                    List<CosemData> actionUpDatas = actionsDatas.get(0).getChild();
                    Integer actionUp = 0;
                    String actionUpLogicalName;
                    Integer actionDown = 0;
                    String actionDownLogicalName;

                    if (actionUpDatas.size() == 2) {
                        actionUpLogicalName = (String)cosemXmlService.getData(actionUpDatas.get(0).getType(), actionUpDatas.get(0).getValue());
                        actionUp = Convert.toInt(cosemXmlService.getData(actionUpDatas.get(1).getType(), actionUpDatas.get(1).getValue()));
                        log.debug("actionUp" + actionUpLogicalName +" " + actionUp);
                    }
                    List<CosemData> actionDownDatas = actionsDatas.get(1).getChild();
                    if (actionDownDatas.size() == 2) {
                        actionDownLogicalName = (String)cosemXmlService.getData(actionDownDatas.get(0).getType(), actionDownDatas.get(0).getValue());
                        actionDown= Convert.toInt(cosemXmlService.getData(actionDownDatas.get(1).getType(), actionDownDatas.get(1).getValue()));
                        log.debug("actionDown" + actionDownLogicalName +" " + actionDown);
                    }
                    Map<String, String> actionMap = new HashMap<>();
                    actionMap.put("limitActionUp", Convert.toStr(actionUp));
                    actionMap.put("limitActionDown", Convert.toStr(actionDown));
                    taskDAO.addTaskData(task.getTaskNo(), atomicTask.getAtomicTaskNo(), operationName.getName(), actionMap, 600L, true);
                }
                if (isSubTaskGroupLastAtomicTask(task, atomicTask)){
                    taskDAO.addTaskData(task.getTaskNo(), atomicTask.getAtomicTaskNo(), SUB_TASK_COMPLETED, true,600L, true);
                }
                break;
        }
        return 1;
    }

    @Override
    public int handleFailure(Task task, AtomicTask atomicTask, String message) {
        log.info("error {}, ", message);
        if (atomicTask.getGroupId() == OperationGroup.GetLoadLimit.getId().intValue()) {
            String stepOperationName = OperationName.forId(atomicTask.getOperationId()).getName();
            if (task.getIsODR()) {
                taskDAO.addTaskData(task.getTaskNo(), atomicTask.getAtomicTaskNo(), stepOperationName, String.format("step %s failed, [%s]", stepOperationName, message), 3600l, false);
            }
        }
        return -1;
    }
}
